////////////////////////////////////////////////////////////////////////////
//
//  Crytek Engine Source File.
//  Copyright (C), Crytek Studios, 2001.
// -------------------------------------------------------------------------
//  File name:   SelectionGroup.h
//  Version:     v1.00
//  Created:     10/10/2001 by Timur.
//  Compilers:   Visual C++ 6.0
//  Description: CSelection group definition.
// -------------------------------------------------------------------------
//  History:
//
////////////////////////////////////////////////////////////////////////////

#ifndef __SelectionGroup_h__
#define __SelectionGroup_h__

#if _MSC_VER > 1000
#pragma once
#endif

class CBaseObject;
class CBrushObject;
class CSolidBrushObject;
class CGeomEntity;

#include "ObjectEvent.h"

/*!
 *	CSelectionGroup is a named selection group of objects.
 */
class CSelectionGroup
{
public:
	CSelectionGroup();

	//! Set name of selection.
	void SetName( const CString &name ) { m_name = name; };
	//! Get name of selection.
	const CString& GetName() const { return m_name; };

	//! Adds object into selection list.
	void AddObject( CBaseObject *obj );
	//! Remove object from selection list.
	void RemoveObject( CBaseObject *obj );
	//! Remove all objects from selection.
	void RemoveAll();
	//! Check if object contained in selection list.
	bool IsContainObject( CBaseObject *obj ) const;
	//! Return true if selection doesnt contain any object.
	bool IsEmpty() const;
	//! Check if all selected objects are of same type
	bool SameObjectType();
	//! Number of selected object.
	int	 GetCount() const;
	//! Number of selected object.
	void	 ObjectModified() const;
	//! Get object at given index.
	CBaseObject* GetObject( int index ) const;

	//! Get mass center of selected objects.
	Vec3	GetCenter() const;

	//! Get Bounding box of selection.
	AABB GetBounds() const;

	//! Number of objects which have flow graph.
	int GetFlowGraphCount() const;

	//! Number of references by other flow graphs.
	int GetFlowGraphReferenceCount() const;

	void	Copy( const CSelectionGroup &from );

	//! Remove from selection group all objects which have parent also in selection group.
	//! And save resulting objects to saveTo selection.
	void	FilterParents();
	//! Get number of child filtered objects.
	int GetFilteredCount() const { return m_filtered.size(); }
	CBaseObject* GetFilteredObject( int i ) const { return m_filtered[i]; }

	//////////////////////////////////////////////////////////////////////////
	// Operations on selection group.
	//////////////////////////////////////////////////////////////////////////
	//! Move objects in selection by offset.
	void Move( const Vec3 &offset,bool keepHeight,int referenceCoordSys );
	//! Move objects in selection to specific position.
	void MoveTo( const Vec3& pos, bool keepHeight, int referenceCoordSys );
	//! Rotate objects in selection by given angle.
	void Rotate( const Ang3 &angles,int referenceCoordSys );
	//! Scale objects in selection by given scale.
	void StartScaling();
	void Scale( const Vec3 &scale,int referenceCoordSys );
	void FinishScaling( const Vec3 &scale,int referenceCoordSys );
	//! Rotate objects in selection by given quaternion.
  void Rotate(const Quat &qRot, int referenceCoordSys);
  //! Rotate objects in selection by given rotation matrix.
  void Rotate(const Matrix34 &matRot, int referenceCoordSys);
  //! Transforms objects
  void Transform(const Vec3 &offset, bool keepHeight, const Ang3 &angles, const Vec3 &scale, int referenceCoordSys);
	//! Resets rotation and scale to identity and (1.0f, 1.0f, 1.0f)
  void ResetTransformation();
	//! Align objects in selection to surface normal
	void Align();
	//! Very special method to move contents of a voxel.
	void MoveContent( const Vec3 &offset);

	//! SegmentedWorld (SW) Helper method: check for position change permission
	bool SWOnSelectionClonePlaceAccept();

	//////////////////////////////////////////////////////////////////////////
	//! Clone objects in this group and add cloned objects to new selection group.
	//! Only topmost parent  objects will be added to this selection group.
	void Clone( CSelectionGroup &newGroup );

	//! Same as Copy but will copy all objects from hierarchy of current selection to new selection group.
	void FlattenHierarchy( CSelectionGroup &newGroup );

	//! Pick new parent and attach selection to it.
	void PickAndAttach();

	// Send event to all objects in selection group.
	void SendEvent( ObjectEvent event );

	// Helper functions to begin and end param editing for all the objects
	// contained in a selection group.
	void BeginEditParams( IEditor *ie,int flags );
	void EndEditParams();
	ULONG STDMETHODCALLTYPE		AddRef();
	ULONG STDMETHODCALLTYPE		Release();

	void IndicateSnappingVertex( DisplayContext &dc ) const;

private:
	CString m_name;
	typedef std::vector<TSmartPtr<CBaseObject> > Objects;
	Objects m_objects;
	// Objects set, for fast searches.
	std::set<CBaseObject*> m_objectsSet;

	//! Selection list with child objecs filtered out.
	std::vector<CBaseObject*> m_filtered;

	bool m_bVertexSnapped;
	Vec3 m_snapVertex;

	const static int SnappingVertexNumThreshold = 700;

	// Description:
	//     Tries to snap a given position to the nearest vertex.
	// Arguments:
	//     pObj - An object to be vertex-snapped. This should be either a brush or a solid
	//     offset - The current offset applied to the object by user input
	// Return Value:
	//     A new offset vector needed to exactly snap to the nearest vertex. Just 'offset' in case that there is no proper snap vertex around.
	Vec3 SnapToCloseVertexIfAny(CBaseObject *pObj, const Vec3& offset);

	void CollectCandidates(std::vector<CBrushObject*>& brushes, 
												std::vector<CSolidBrushObject*>& solids,
												std::vector<CGeomEntity*>& entities,
												CBaseObject * pObj, const Vec3& offset);
	Vec3 FindNearestSnapVertex(std::vector<Vec3> &srcVertices, const Vec3& offset, 
														const std::vector<CBrushObject*>& brushes, 
														const std::vector<CSolidBrushObject*>& solids,
														const std::vector<CGeomEntity*>& entities);

protected:
	ULONG	m_ref;
};

#endif // __SelectionGroup_h__
